package egr::Persist;
use strict;

# System supplied modules
use DBI;

# direct perl to use modules in our /lib folder
use lib qw(./lib);

use egr::Constants;
###############################################################################
# Begin Package Code
###############################################################################
sub new
{
    my $type = shift;
    my $this = {};          # allocate anon hash mem for new class
    bless ($this, $type);
    $this->_init(@_);       # init w/remaining params
    return $this;
}

#
# Open a connection as soon as we can and reuse it throughout the
# module.
# 
sub _init
{
    my $this = shift;
    $this->{dbh} = Connect();
}

sub Connect
{
    my $host   = egr::Constants::CONN_HOST;
    my $dbname = egr::Constants::CONN_DB;
    my $user   = egr::Constants::CONN_USER;
    my $passwd = egr::Constants::CONN_PASSWD;

    my $dbh = DBI->connect
        ("DBI:mysql:host=$host;database=$dbname", $user, $passwd)
            or die "Couldn't connect to database: " . DBI->errstr;

    return $dbh;
}

sub prjPutRecord
{
    my $this    = shift;
    my $prjName = shift;
    my $id      = shift;
    my $type    = shift;
    my $val     = shift;

    my $dbh = $this->{dbh};
    my $sql = "insert into `$prjName` values (?, ?, ?);";

    my $sth = $dbh->prepare($sql)
        or die "Couldn't prepare statement: " . $dbh->errstr;

    $sth->execute($id, $type, $val) # Execute the query
        or die "Couldn't execute statement: " . $sth->errstr;    
}

sub printRecord
{
    my $this = shift;
    my $id   = shift;
    my $typ  = shift;
    my $val  = shift;

    print "id\ttyp\tval\n";
    print "=================================================================\n";
    print "$id\t$typ\t$val\n";
}

sub prjGetRecordById
{
    my $this    = shift;
    my $prjName = shift;
    my $id      = shift;

    my $dbh = $this->{dbh};
    my $sql = "select type,val from `$prjName` where id = ?;";

    my $sth = $dbh->prepare($sql)
        or die "Couldn't prepare statement: " . $dbh->errstr;

    $sth->execute($id)
        or die "Couldn't execute statement: " . $sth->errstr;    

    my @data = $sth->fetchrow_array();
    unshift(@data, $id);
    return @data;
}

sub prjGetRecordByType
{
    my $this    = shift;
    my $prjName = shift;
    my $type    = shift;

    my $dbh = $this->{dbh};
    my $sql = "select id,val from `$prjName` where type = ?;";

    my $sth = $dbh->prepare($sql)
        or die "Couldn't prepare statement: " . $dbh->errstr;

    $sth->execute($type) # Execute the query
        or die "Couldn't execute statement: " . $sth->errstr;

    while (my @data = $sth->fetchrow_array())
    {
        my $id   = $data[0];
        my $val  = $data[1];
        print "\t$id,$type,$val\n";
    }
}

sub prjExists
{
    my $this = shift;
    return 0;
}

sub prjCreate
{
    my $this    = shift;
    my $prjName = shift;

    my $dbh = $this->{dbh};

    if ($this->prjExists($prjName))
    {
        return;
    }

    my $sql = <<SQL;
CREATE TABLE IF NOT EXISTS `egr_$prjName`
(
    id  BIGINT UNSIGNED,
    typ BIGINT UNSIGNED,
    val BLOB
);
SQL

    my $sth = $dbh->prepare($sql)
        or die "Couldn't prepare statement: " . $dbh->errstr;

    $sth->execute() # Execute the query
        or die "Couldn't execute statement: " . $sth->errstr;
}

1; # keep perl from screaming
__END__
=head1 NAME

Persist.pm - EGR Persistence Engine

=head1 SYNOPSIS

=head1 DESCRIPTION

The Persist module is the bit of code that talks to the database. It's job is pretty straightforward, connect to a project in the database and manipuate the project table. The module has various helper functions to simplify the process. 

=head2 DATABASE

It's hard to talk about the Persist module without discussing the database model. Actually there isn't much of a model to start with, we only use a database for storage, and don't want or use any relational database features. We will probably move away from a database in the future and just use binary file access.

Every EGR project consists of one table in a MySQL database. The table has a random name, so you can't assume that a table name is the a proect. This table contains three fields, id, typ, and val. We should be able to create/modify any type of data structure with these fields including: lists and tress.

=head3 id

The id field, is an unsigned bigint and is the row primary key. It is a unuque value, that has no bearing on the other values.

=head3 typ

The typ field is very important. It tells us what type of data the val field contains. Type is a very fluid concept and has little to do with datatypes, but doesn't exclude it. It's an integer value and its meaning is defined in the Constants.pm module. Types can/will come and go throughout the lifetime of the EGR project. It tells us how to interpret the data stored in the next field.

=head3 val

The val field is a binary blob that stores data related to the record. It can contain anything and it's meaning is completly dependent on typ.

=head1 COPYRIGHT

Copyright 2008 Jon Chick <chick.jon@egather.org>.

Permission is granted to copy, distribute and/or modify this 
document under the terms of the GNU Free Documentation 
License, Version 1.2 or any later version published by the 
Free Software Foundation; with no Invariant Sections, with 
no Front-Cover Texts, and with no Back-Cover Texts.

=cut
